package linc.fun.common.rest.http.aspect;

import linc.fun.common.core.utils.JsonUtils;
import linc.fun.common.rest.http.annotation.RestAsync;
import linc.fun.common.rest.http.request.JsonRestRequest;
import linc.fun.common.rest.http.service.JsonRestService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;

/**
 * @author yqlin
 * @date 2022/5/5 17:56
 * @description
 */
@Component
@Aspect
@Slf4j
public class JsonRestControllerAdvice {
    private final JsonRestService service;
    private final Executor executor;

    @Autowired
    public JsonRestControllerAdvice(JsonRestService jsonRestService, @Qualifier("async-service") Executor executor) {
        this.service = jsonRestService;
        this.executor = executor;
    }

    @Pointcut("@annotation(linc.fun.common.rest.http.annotation.RestAsync)")
    final protected void mappingPointcut() {
    }

    @Around("mappingPointcut() && args(req)")
    private Object runAsync(final ProceedingJoinPoint pjp, JsonRestRequest req) throws Throwable {
        log.debug("app advice start...");
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        assert sra != null;
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        CompletableFuture<?> cf;
        Object[] args = pjp.getArgs();
        log.info("请求数据: \n {}", JsonUtils.printJson(args));
        RestAsync restAsync = method.getAnnotation(RestAsync.class);
        if (Objects.nonNull(restAsync)) {
            cf = restAsync.async() ? CompletableFuture.supplyAsync(() -> service.rest(req), executor) : CompletableFuture.completedFuture(service.rest(req));
        } else {
            cf = (CompletableFuture<?>) pjp.proceed();
        }
        cf.whenComplete((o, t) -> {
            if (Objects.nonNull(t)) {
                log.error(t.getMessage(), t);
            }
            if (Objects.nonNull(o)) {
                log.debug("返回数据: \n {}", JsonUtils.printJson(o));
            }
        });
        log.info("rest handled...");
        return cf;
    }
}
